#pragma once

#include <cstddef>
#include <utility>

/**
 * @brief 第九版本：自定义删除器支持与 get_deleter。
 *
 * 重点：
 *   - get_deleter 返回删除器引用，允许外部观察或调用。
 *   - reset 新增重载，可同时替换指针与删除器。
 */
template <typename T, typename Deleter = void(*)(T*)>
class UniquePtr {
public:
    using pointer      = T*;
    using element_type = T;
    using deleter_type = Deleter;

    static void default_delete(T* ptr) noexcept {
        delete ptr;
    }

    constexpr UniquePtr() noexcept
        : ptr_(nullptr)
        , deleter_(default_delete) {}

    constexpr UniquePtr(std::nullptr_t) noexcept
        : UniquePtr() {}

    explicit UniquePtr(pointer ptr) noexcept
        : ptr_(ptr)
        , deleter_(default_delete) {}

    UniquePtr(pointer ptr, deleter_type deleter) noexcept
        : ptr_(ptr)
        , deleter_(std::move(deleter)) {}

    UniquePtr(const UniquePtr&)            = delete;
    UniquePtr& operator=(const UniquePtr&) = delete;

    UniquePtr(UniquePtr&& other) noexcept
        : ptr_(other.ptr_)
        , deleter_(std::move(other.deleter_)) {
        other.ptr_ = nullptr;
    }

    UniquePtr& operator=(UniquePtr&& other) noexcept {
        if (this != &other) {
            reset();
            ptr_     = other.ptr_;
            deleter_ = std::move(other.deleter_);
            other.ptr_ = nullptr;
        }
        return *this;
    }

    ~UniquePtr() {
        reset();
    }

    void swap(UniquePtr& other) noexcept {
        std::swap(ptr_, other.ptr_);
        std::swap(deleter_, other.deleter_);
    }

    /**
     * @brief reset 重载：更新指针同时可更新删除器。
     *
     * 先调用单参 reset 释放旧资源并接管新指针，然后替换删除器。
     */
    void reset(pointer ptr, deleter_type deleter) noexcept {
        reset(ptr);                     // 复用已有逻辑：释放旧、接管新
        deleter_ = std::move(deleter);  // 更新删除器
    }

    void reset(pointer ptr = nullptr) noexcept {
        if (ptr_) {
            deleter_(ptr_);
        }
        ptr_ = ptr;
    }

    pointer release() noexcept {
        pointer raw = ptr_;
        ptr_ = nullptr;
        return raw;
    }

    pointer get() const noexcept {
        return ptr_;
    }

    element_type& operator*() const noexcept {
        return *ptr_;
    }

    pointer operator->() const noexcept {
        return ptr_;
    }

    explicit operator bool() const noexcept {
        return ptr_ != nullptr;
    }

    /// 返回删除器的可修改引用，允许外部直接调用或替换（若删除器类型可赋值）
    deleter_type& get_deleter() noexcept {
        return deleter_;
    }

    /// const 版本的 get_deleter，允许在常量上下文中访问
    const deleter_type& get_deleter() const noexcept {
        return deleter_;
    }

private:
    pointer      ptr_{nullptr};
    deleter_type deleter_{default_delete};
};

template <typename T, typename Deleter>
void swap(UniquePtr<T, Deleter>& lhs, UniquePtr<T, Deleter>& rhs) noexcept {
    lhs.swap(rhs);
}